from CommandWriter import *
from StateReader import *
#from ReadFlags import *
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfilename
import operator

#Array of buttons, for quick access
gridButtons = []
#Command cache for clicking buttons, basically acts as a queue.
commandCache = []
#Our set of alive cells for the current generation
cellGrid = set()
#Current width in buttons
currentWidth = 51
#Current height in buttons
currentHeight = 25
#Time for keypress delay
currentTime = time.time()

#Panning shift values
xShift = 0
yShift = 0
newXShift = 0
newYShift = 0

class LifeLike():

    #Paused boolean for panning while playing
    #or while paused
    paused = True
    #Block boolean for telling the poll thread
    #that we've panned
    panBlock = False
    
    # get a cell grid
    def getCellGrid(self):
        global cellGrid
        return cellGrid
    
    def getxShift(self):
        global xShift
        return xShift
    
    def getyShift(self):
        global yShift
        return yShift
    
    #Translates Python based coordinates to ACL2
    #based coordinates
    def pyToACL2Coord(self, x, y):
        xOffSet = (currentWidth-1)/2
        yOffSet = (currentHeight-1)/2
        return (int(x-xOffSet), int(-(y-yOffSet)))
        
    #Translates ACL2 based coordinates to Python
    #based coordinates
    def acl2ToPyCoord(self, x, y):
        xOffSet = (currentWidth-1)/2
        yOffSet = (currentHeight-1)/2
        return (int(x+xOffSet), int(-y+yOffSet))
        
    #set the color of a cell to white(on)
    def setButtonToWhite(self, x, y):
        if x < 0 or y < 0 or x >= len(gridButtons) or y >= len(gridButtons[x]):
            return
        button = gridButtons[x][y]
        button["bg"] = "WHITE"
        
    #set the color of a cell to black (off)
    def setButtonToBlack(self, x, y):
        if x < 0 or y < 0 or x >= len(gridButtons) or y >= len(gridButtons[x]):
            return
        button = gridButtons[x][y]
        button["bg"] = "BLACK"

    #Given the new set of coordinates, turn off
    #cells that died and turn on cells that were
    #born
    def handleACL2Coordinates(self, coords):
        #cellGrid is the set of cells currently alive,
        #according to python
        global cellGrid

        #convert ACL2 coordinates to python coordinates
        pyCoords = set()
        for coord in coords:
            pyCoords.add(self.acl2ToPyCoord(coord[0], coord[1]))
        
        deadCoords = cellGrid - pyCoords
        
        bornCoords = pyCoords - cellGrid
        
        for coord in deadCoords:
            x,y = coord
            self.setButtonToBlack(x+xShift,y+yShift)

        for coord in bornCoords:
            x,y = coord
            self.setButtonToWhite(x+xShift,y+yShift)

        cellGrid = pyCoords
            
    #set a cell to on when it was clicked in python
    def handlePythonCoordinate(self, x, y):
        coord = (x, y)
        
        if coord in cellGrid:
            cellGrid.remove(coord)
            self.setButtonToBlack(x+xShift, y+yShift)
        else:
            cellGrid.add(coord)
            self.setButtonToWhite(x+xShift, y+yShift)
            
    #write out to the command chache when the user presses a button
    def buttonPressed(self, text):
        commandCache.append(text)
        print(text)
        WriteCommand(commandCache)

    #special version of buttonPressed for grid cells since
    #they require including params as well
    def gridButtonPressed(self, x, y):
        x -= xShift
        y -= yShift
        
        coord = self.pyToACL2Coord(x, y)
        newX, newY = (coord)
        
        cell = (x, y)
        if cell in cellGrid:
            command = "set-cell " + str(newX) + " " + str(newY) + " false"
        else:
            command = "set-cell " + str(newX) + " " + str(newY) + " true"
        
        self.handlePythonCoordinate(x, y)
        
        commandCache.append(command)
        WriteCommand(commandCache)
    
    #Rewrite a clean Grid. Doesnt actually change
    #cellGrid, just the gui Grid
    def updateGui(self):
        global xShift
        global yShift
        for coord in cellGrid:
            x, y = (coord)
            self.setButtonToWhite(x+newXShift, y+newYShift)
        xShift = newXShift
        yShift = newYShift
    
    #Clean the Grid. Doesnt actually change
    #cellGrid, just the gui Grid
    def clearGui(self):
        for coord in cellGrid:
            x, y = (coord)
            self.setButtonToBlack(x+xShift, y+yShift)
    
    #The key pressed event handler
    def key(self, event):
        global xShift
        global yShift
        global newXShift
        global newYShift
        global currentTime
        
        if time.time() - currentTime < .1:
            return
        currentTime = time.time()
        
        if event.keysym == 'Right':
            newXShift = xShift + 1
        if event.keysym == 'Left':
            newXShift = xShift + -1
        if event.keysym == 'Up':
            newYShift = yShift + -1
        if event.keysym == 'Down':
            newYShift = yShift + 1
            
        self.panBlock = True
        
        #If we are paused, then we need to update ourselves.
        if self.paused == True:
            self.clearGui()
            self.updateGui()

    #Handles loading and saving images
    def handle_file_button_command(self, command_name):
        filename = ""
        
        if command_name == "save-img":
            filename = asksaveasfilename(title="Save Your Automaton", defaultextension = '.bmp', filetypes=[("Bitmaps", ".bmp")])
        else:
            filename = askopenfilename(title="Select an Automaton to Load", defaultextension = '.bmp', filetypes=[("Bitmaps", ".bmp")])

        print(filename)
        if filename != "":
            if command_name == "load-img":
                self.clearGui()
                global cellGrid
                global xShift
                global yShift
                global newXShift
                global newYShift
                xShift = 0
                yShift = 0
                newXShift = 0
                newYShift = 0
                cellGrid = set()
            self.buttonPressed(command_name + " " + filename)

    #Activates and Deactivates button for a more fluid user experience
    def pause_play_control(self, action):
        global playButton
        global pauseButton
        global reverseButton
        global saveButton
        global loadButton
        global ffButton
        #import pdb; pdb.set_trace()
        #GUI Update to make sure that the action followed up.
        if action == "play":
                        #import pdb; pdb.set_trace()
            playButton.config(state = DISABLED)
            pauseButton.config(state = NORMAL)
            ffButton.config(state = NORMAL)
            saveButton.config(state = DISABLED)
            loadButton.config(state = DISABLED)
            reverseButton.config(state = NORMAL)
            with open('rev','w') as fd:
                            fd.write('false')
            self.paused = False
        elif action == "fast-forward":
            ffButton.config(state = DISABLED)
            playButton.config(state = NORMAL)
        elif action == "reverse":
            ffButton.config(state = DISABLED)
            playButton.config(state = NORMAL)
            with open('rev','w') as fd:
                                fd.write('true')
        else:
            playButton.config(state = NORMAL)
            pauseButton.config(state = DISABLED)
            ffButton.config(state = DISABLED)
            saveButton.config(state = NORMAL)
            loadButton.config(state = NORMAL)
            if action == "pause":
                self.paused = True
            
        if action == "reverse":
            pass
        else:
            self.buttonPressed(action) #Handle the action

    #The init method. Constructs our frame, buttons, and grid
    #and binds the key press listener.
    def __init__(self, root):
        frame = Frame(root)
        frame.pack(side=LEFT, expand=1)
        
        gridFrame = Frame(root)
        gridFrame.pack(side=RIGHT, expand=1)
        Grid.rowconfigure(frame,7,weight=1)
        Grid.columnconfigure(frame,0,weight=1)
        
        global playButton
        playButton = Button(frame, text="Play", command = lambda: self.pause_play_control("play"))
        playButton.grid(row=0, column=0, padx=5, pady=5)
        global pauseButton
        pauseButton = Button(frame, text="Pause", command = lambda: self.pause_play_control("pause"))
        pauseButton.grid(row=1, column=0, padx=5, pady=5)
        pauseButton.config(state = DISABLED)
        global ffButton 
        ffButton = Button(frame, text="Fast Forward", command = lambda: self.pause_play_control("fast-forward"))
        ffButton.grid(row=2, column=0, padx=5, pady=5)
        ffButton.config(state = DISABLED)
        global reverseButton 
        reverseButton = Button(frame, text="Reverse", command = lambda: self.pause_play_control("reverse"))
        reverseButton.grid(row=3, column=0, padx=5, pady=5)
        reverseButton.config(state = DISABLED)
        global saveButton
        saveButton = Button(frame, text="Save", command = lambda: self.handle_file_button_command("save-img"))
        saveButton.grid(row=4, column=0, padx=5, pady=5)
        global loadButton
        loadButton = Button(frame, text="Load", command = lambda: self.handle_file_button_command("load-img"))
        loadButton.grid(row=5, column=0, padx=5, pady=5)
        
        print("Lanching lifelike grid!")
        for x in range(currentWidth):
            gridColumn = []
            for y in range(currentHeight):
                cellColumn = x
                cellRow = y
                button = Button(gridFrame, background="BLACK", command = lambda cellColumn=x, cellRow=y: self.gridButtonPressed(cellColumn, cellRow))
                button.grid(row=y, column=x, ipadx=3, sticky=N+S+E+W)
                gridColumn.append(button)
            gridButtons.append(gridColumn)
        
        
        frame.bind_all('<Key>', self.key)
111111111111111
